package com.sz.biz.common.base.service.impl;

import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.LanguageCode;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.common.base.entity.Country;
import com.sz.biz.common.base.service.AreaManager;
import com.sz.biz.common.base.dto.AreaDto;
import com.sz.biz.common.base.dto.CountryDto;
import com.sz.common.base.cache.EntityCache;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.Dao;
import com.sz.common.base.dao.Pagination;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.base.utils.StringUtils;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.service.PrincipalUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Function: AreaManagerImpl <br>
 * Author: penghui.zheng <br>
 * Date: 2016-11-09 13:41:00
 */
@Service("areaManager")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class AreaManagerImpl extends AbstractService implements AreaManager {

    @Resource(name = "daoSupport")
    private Dao dao;

    @Override
    protected String getMapperNamespace() {
        return null;
    }

    @Override
    public void refreshCountryCache() {
        EntityCache.clearNamespace("CountryMapper");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer saveArea(AreaDto areaDto) {
        ParamData pd = new ParamData();
        pd.put("name", areaDto.getName());
        pd.put("figureCode", areaDto.getFigureCode());
        pd.put("triadCode", areaDto.getTriadCode());
        pd.put("areaCode", areaDto.getAreaCode());
        pd.put("parentId", areaDto.getParentId());
        String countryCode = areaDto.getCountryCode();
        Integer id = save(countryCode, ".insertSelective", areaDto, pd);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("ADD_COUNTRY", areaDto);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_COUNTRY, UserActions.ADD, "新建国家", dataBackup);
        return id;
    }

    @Override
    public Integer updateArea(AreaDto areaDto) {
        ParamData pd = new ParamData();
        pd.put("name", areaDto.getName());
        pd.put("id", areaDto.getId());
        pd.put("parentId", areaDto.getParentId());
        String countryCode = areaDto.getCountryCode();
        Integer id = save(countryCode, ".updateByPrimaryKeySelective", areaDto, pd);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_COUNTRY", areaDto);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_COUNTRY, UserActions.UPDATE, "修改国家", dataBackup);
        return id;
    }

    private Integer save(String countryCode, String fun, AreaDto areaDto, ParamData pd) {
        String reg = "[A-Z]+";
        Country country = new Country();
        EntityUtils.copyPropertiesIgnoreNull(areaDto, country);
        if (!StringUtils.isEmpty(areaDto.getId())) {
            country.setId(Integer.parseInt(areaDto.getId()));
        }
        boolean isCractByFigureCode = country.getFigureCode().toUpperCase().matches(reg);
        if (!isCractByFigureCode) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_FIGURECODE_NOT_CHARACTER);
        }
        boolean isCractByTriadCode = country.getTriadCode().toUpperCase().matches(reg);
        if (!isCractByTriadCode) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_TRIADCODE_NOT_CHARACTER);
        }
        if (countryCode == null || "".equals(countryCode)) {
            // 检查数据不能重复
            Country figureCodeExist = (Country) dao.findForObject("CountryMapper.findByFigureCode", pd);
            if (figureCodeExist != null) {
                throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_FIGURECODE_EXIST);
            }
            dao.save("CountryMapper" + fun, country);
        }
        return country.getId();
    }

    @Override
    public void deleteByAreaId(String id, String countryCode) {
        int countryId = Integer.parseInt(id);
        ParamData pd = new ParamData();
        if (countryCode == null || "".equals(countryCode)) {
            pd.put("id", countryId);
            CountryDto countryExist = (CountryDto) dao.findForObject("CountryMapper.findByAreaId", pd);
            if (countryExist == null) {
                throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_NOT_FOUND, id);
            }
            if (countryExist.getIsDeleted()) {
                throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_HAS_BEEN_DELETED, id);
            }
            dao.update("CountryMapper.deleteByAreaId", id);
        } else {
            pd.put("id", id);
            if (LanguageCode.CN_UPPER.equals(countryCode)) {
                // 检查数据不能重复
                AreaDto areaExist = (AreaDto) dao.findForObject("AreaCNMapper.findByAreaId", pd);
                if (areaExist == null) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_NOT_FOUND, id);
                }
                if (areaExist.getIsDeleted()) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_HAS_BEEN_DELETED, id);
                }
                dao.update("AreaCNMapper.deleteByAreaId", id);
            } else {
                pd.put("id", id);
                // 检查数据不能重复
                AreaDto areaExist = (AreaDto) dao.findForObject("AreaMapper.findByAreaId", pd);
                if (areaExist == null) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_NOT_FOUND, id);
                }
                if (areaExist.getIsDeleted()) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_HAS_BEEN_DELETED, id);
                }
                dao.update("AreaMapper.deleteByAreaId", id);
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteByCountryIds(List<Integer> ids) {
        dao.update("CountryMapper.deleteByIds", ids);
        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("DELETE_COUNTRY", ids);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_COUNTRY, UserActions.DELETE, "删除国家", dataBackup);
    }


    /**
     * 异步校验国家地区编码
     *
     * @param areaCode
     */
    @Override
    public void checkAreaCode(String areaCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("areaCode", areaCode);
        Country countryExist = (Country) dao.findForObject("CountryMapper.findByAreaCode", map);
        if (countryExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_AREACODE_EXIST);
        }
    }

    /**
     * 异步校验国家二字码
     *
     * @param figureCode
     */
    @Override
    public void checkFigureCode(String figureCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("figureCode", figureCode);
        Country countryExist = (Country) dao.findForObject("CountryMapper.findByFigureCode", map);
        if (countryExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_FIGURECODE_EXIST);
        }
    }

    /**
     * 异步校验国家三字码
     *
     * @param triadCode
     */
    @Override
    public void checkTriadCode(String triadCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("triadCode", triadCode);
        Country countryExist = (Country) dao.findForObject("CountryMapper.findByTriadCode", map);
        if (countryExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_TRIADCODE_EXIST);
        }
    }

    /**
     * 国家名称校验
     *
     * @param name
     */
    @Override
    public void checkCountryName(String name) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", name);
        Country countryExist = (Country) dao.findForObject("CountryMapper.findByAreaName", map);
        if (countryExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_AREA_AREANAME_EXIST);
        }
    }


    @Override
    public ResultDto findAreaList(String countryCode, String parentId, String q, int pageIndex, int pageSize) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        List<Country> allList = dao.findForList("CountryMapper" + ".findArea", pd, Country.class);
        if (!StringUtils.isEmpty(q)) {
            pd.put("q", q);
            List<Country> qList = dao.findForList("CountryMapper" + ".findArea", pd, Country.class);
            List<String> ids = new ArrayList<String>();
            for (Country country : qList) {
                ids.add(country.getFigureCode());
            }
            if (ids.size() > 0) {
                pd.put("ids", ids);
            }
        }
        pd.put("parentId", parentId);
        pd.put("language", language);
        Pagination page = new Pagination();
        page.setCurrentPage(pageIndex);
        page.setPageSize(pageSize);
        pd.setPagination(page);
        QResultDto dto = new QResultDto();
        List<AreaDto> list = findArea(countryCode, ".areaListPage", parentId, pd);
        for (AreaDto areaDto : list) {
            for (Country country : allList) {
                if (areaDto.getParentId().equals(country.getFigureCode())) {
                    areaDto.setName(country.getName());
                }
            }
        }
        dto.setData(list);
        dto.setPagination(page);
        return dto;
    }

    @Override
    public ResultDto findByParentId(String countryCode, String parentId, String q, int pageIndex, int pageSize) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("language", language);
        pd.put("q", q);
        Pagination page = new Pagination();
        page.setCurrentPage(pageIndex);
        page.setPageSize(pageSize);
        pd.setPagination(page);
        QResultDto dto = new QResultDto();
        List<AreaDto> list = null;
        if (LanguageCode.CN_UPPER.equals(countryCode)) {
            list = findArea(countryCode, ".findAreaListPage", parentId, pd);
        } else {
            list = findArea(countryCode, ".findAreaListPage", parentId, pd);
        }

        dto.setData(list);
        dto.setPagination(page);
        return dto;
    }

    @Override
    public List<AreaDto> findByAreaId(String countryCode, String id) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("language", language);
        List<AreaDto> list;
        pd.put("id", id);
        if (LanguageCode.CN_UPPER.equals(countryCode)) {
            list = dao.findForList("AreaCNMapper.findByAreaId", pd, AreaDto.class);
        } else {
            list = dao.findForList("AreaMapper.findByAreaId", pd, AreaDto.class);
        }
        return list;
    }

    private List<AreaDto> findArea(String countryCode, String fun, String parentId, ParamData pd) {
        List<AreaDto> list;
        if (countryCode == null) {
            pd.put("parentId", parentId);
            list = dao.findForList("AreaMapper" + fun, pd, AreaDto.class);
            return list;
        } else {
            if (LanguageCode.CN_UPPER.equals(countryCode)) {
                if (LanguageCode.CN_UPPER.equals(parentId)) {
                    pd.put("parentId", '0');
                } else {
                    pd.put("parentId", parentId);
                }
                list = dao.findForList("AreaCNMapper" + fun, pd, AreaDto.class);
                return list;
            } else {
                pd.put("parentId", parentId);
                list = dao.findForList("AreaMapper" + fun, pd, AreaDto.class);
                return list;
            }
        }
    }


    @SuppressWarnings("rawtypes")
    @Override
    public ResultDto findI18nByParam(QueryParams params, String countryCode, String parentId) {
        ParamData pd = this.convertQueryParams(params);
        pd.put("parentId", parentId);
        if (StringUtils.isEmpty(countryCode)) {
            List<Map> entry = dao.findForList("CountryMapper" + ".findI18nByParamListPage", pd, Map.class);
            QResultDto dto = new QResultDto(entry, pd.getPagination());
            return dto;
        } else {
            if (LanguageCode.CN_UPPER.equals(countryCode)) {
                List<Map> entry = dao.findForList("AreaCNMapper" + ".findI18nByParamListPage", pd, Map.class);
                QResultDto dto = new QResultDto(entry, pd.getPagination());
                return dto;
            } else {
                List<Map> entry = dao.findForList("AreaMapper" + ".findI18nByParamListPage", pd, Map.class);
                QResultDto dto = new QResultDto(entry, pd.getPagination());
                return dto;
            }
        }
    }

    @Override
    public CountryDto findByCountryId(int id) {
        ParamData pd = new ParamData();
        pd.put("id", id);
        CountryDto countryDto = (CountryDto) dao.findForObject("CountryMapper.findByAreaId", pd);
 
        return countryDto;
    }

    @Override
    public Country findByCountryCode(String figureCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("figureCode", figureCode);
        return (Country) dao.findForObject("CountryMapper.findByFigureCode", map);
    }

    @Override
    public ResultDto findCountryList(QueryParams params) {
        String language = PrincipalUtils.getLocalLanguage();
        params.setLanguage(language);
        ParamData pd = this.convertQueryParams(params);
        List<Country> list = dao.findForList("CountryMapper" + ".findAreaListPage", pd, Country.class);
        QResultDto dto = new QResultDto();
        dto.setData(list);
        dto.setPagination(pd.getPagination());
        return dto;
    }
}
